#include "config.h"
#include "Game.h"

#include <iostream>
#include <fstream>
using namespace std;

// when parsing is complete, this is the document root
XMLNode* pCurNode = NULL;

// this is called by expat when a new XML node is started
// (we move our pointer down to the new node)
void beginParseElement(void *data, const char *el, const char **attrArray) {
//  cout << "Inside beginParseElement( , " << el << ", )" << endl;

  // save parent node
  XMLNode* pParent = pCurNode; // ? pCurNode->parentNode : NULL);

  // create new XML node
//  cout << "pCurNode was " << pCurNode << " with parent " << pParent;
  pCurNode = new XMLNode();
  pCurNode->tagName = el;

  // link new node back to its parent, link parent to its new child
  pCurNode->parentNode = pParent;
  if(pParent) {
    pParent->children.push_back(pCurNode);
  }
//  cout << ", now pCurNode is " << pCurNode << ", tagname=" << pCurNode->tagName << " with parent " << pCurNode->parentNode << endl;

  for(int i = 0; attrArray[i]; i += 2) {
    // store this attribute name-value in the current node's map
    pCurNode->attr[ attrArray[i] ] = attrArray[i + 1];
  }
}

// this is called by expat when a text node is encountered
// we append a text node to the current object's children
void parseCharacterData(void *data, const char *s, int len) {
//  cout << "Inside parseCharacterData( , " << s << ", " << len << ")" << endl;

  XMLNode* pTextNode = new XMLNode();
  pTextNode->parentNode = pCurNode;

  char* szTemp = new char[len];
  strncpy(szTemp, s, len);
  pTextNode->textContent = szTemp;
  delete[] szTemp;

  pCurNode->children.push_back(pTextNode);
}

// this is called by expat when the current XML node is completed
// (we move our pointer back to the parent node)
void endParseElement(void *data, const char *el) {
//  cout << "inside endParseElement( , " << el << ")" << endl;
//  cout << "pCurNode was " << pCurNode;

  // end this node and step back to the parent
  if(pCurNode && pCurNode->parentNode) {
    pCurNode = pCurNode->parentNode;
  }
//  cout << ", now pCurNode is " << pCurNode << endl;
}

XMLNode* Game::InitConfig(const char* szConfigFilename) {
  cout << "Opening config file '" << szConfigFilename << "'" << endl;

  // must set to NULL, because the Game owns the Config object once
  // this function returns and will delete it upon Game destruction
  // (leaving this pointer dangling)
  pCurNode = NULL;

  XML_Parser p = XML_ParserCreate(NULL);
  if (! p) {
    cerr << "Couldn't allocate memory for parser\n" << endl;
    exit(-1);
  }

  // read in the file into a buffer
  char* Buff = NULL;
  size_t size;
  ifstream file(szConfigFilename, ios::in|ios::ate);
  if(file.is_open())
  {
    size = file.tellg();
    Buff = new char[size];
    file.seekg(0, ios::beg);
    file.read(Buff, size);
    file.close();
    cout << "The complete config file content is in memory" << endl;
  }
  else {
    cerr << "Unable to open config file" << endl;
    exit(1);
  }

  XML_SetElementHandler(p, beginParseElement, endParseElement);
//  XML_SetCharacterDataHandler(p, parseCharacterData);

//  for (;;) {
//    int done;

    if (! XML_Parse(p, Buff, size, 1)) {
      cerr << "Parse error at line " <<
          XML_GetCurrentLineNumber(p) << ":" << endl <<
          XML_ErrorString(XML_GetErrorCode(p)) << endl;
      exit(-1);
    }

//    if (done)
//      break;
//  }

  cout << "Finished parsing config file" << endl;

  // cleanup
  delete[] Buff;
  XML_ParserFree(p);

  return pCurNode;
}
